/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package threading_webserver;

//import com.sun.tools.javac.util.Paths;
import java.io.*;
import java.net.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.Level;
import org.json.Cookie;
import org.json.JSONException;
import org.json.JSONObject;
import threading_webserver.model.User;

/**
 *
 * @author Koen
 */
public class Http_Handler extends Thread {

    private Server server;
    private BufferedReader input;
    private DataOutputStream output;
    private String path;
    private int contentlength;
    private String ipAddress;
    private String setCookie;
    private String getCookieUsername;
    private PortListener listener;
    private Logger logger;
    private String urlRequest;

    public Http_Handler(Server server, BufferedReader input, DataOutputStream output, String ipAddress, PortListener l, Logger logger) {
        this.server = server;
        this.input = input;
        this.output = output;
        this.ipAddress = ipAddress;
        this.listener = l;
        this.logger = logger;
        log(DatabaseConnector.OpenConnection());
        this.start();
    }

    public void log(String s2) {
        if (path != "" && path != null) {
            server.log(path + "  -  " + s2);
        } else {
            server.log(s2);
        }
    }

    @Override
    public void run() {
        long startTime = System.currentTimeMillis();
        path = "";
        try {
            String request = input.readLine();
            String tmp = "";
            String tmp2 = request;
            while (!(tmp = input.readLine()).equals("")) {
                if (tmp.startsWith("Content-Length")) {
                    contentlength = Integer.parseInt(tmp.substring(16));
                    log("Content-Length: " + contentlength + " \n");
                }
                if (tmp.startsWith("Referer")) {
                    urlRequest = tmp.substring(9);
                }
                
                if(tmp.startsWith("Cookie")) {
                    getCookieUsername = tmp.substring(15);
                }
            }
            tmp2.toUpperCase();
            if (tmp2.startsWith("GET")) {
                getMethod(request);
            } else if (tmp2.startsWith("POST")) {
                char[] buffer = new char[contentlength];
                input.read(buffer);
                postMethod(new String(buffer));
            } else {
                try {
                    constructErrorPage(400);
                    return;
                } catch (Exception e3) {
                    log("error method: " + e3.getMessage());
                }
            }
        } catch (Exception e) {
            log("error: " + e.toString());
        }

        long elapsedTime = System.currentTimeMillis() - startTime;
        DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        Date date = new Date();
        if(urlRequest != null)
            this.logger.WriteToLog(ipAddress, dateFormat.format(date), urlRequest, (int) elapsedTime);
        log("Tijdsduur - " + elapsedTime + "ms, Datum: " + dateFormat.format(date) + "\n");
        Server.activeThreads--;
        log("httpHandler: active threads:" + Server.activeThreads);
    }

    public void login(String username, String password) {
        try {
            int retval = DatabaseConnector.CheckLoginData(username, password);

            if (retval > 0) {
                String accLvl = retval == 1 ? "admin" : "support";
                log(String.format("Logged in as '%s' (%s)", username, accLvl));
                setCookie = "Set-Cookie: UserID=" + username + "; Max-Age=6; Version=1; \r\n";
                DatabaseConnector.LogUser(username, 1);
                output.writeBytes(construct_http_header_type(200, 0, 0));
            } else {
                log("Login failed");
                constructErrorPage(500);
            }
        } catch (IOException ex) {
            java.util.logging.Logger.getLogger(Http_Handler.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void postMethod(String request) throws IOException {
        int oldWebport = Settings.webPort;
        int oldControlport = Settings.controlPort;
        try {
            log("Post string: " + request);
            JSONObject jsonRequest = new JSONObject(request);
            String submit = jsonRequest.getString("submit");

            switch (submit) {
                case "login":
                    String user = jsonRequest.getString("username");
                    String pass = jsonRequest.getString("password");
                    login(user, pass);
                    break;
                case "Ok":
                    Settings.webPort = Integer.parseInt(jsonRequest.getString("webport"));
                    Settings.controlPort = Integer.parseInt(jsonRequest.getString("controlport"));
                    Settings.webRoot = jsonRequest.getString("webroot");
                    Settings.defaultPages[0] = jsonRequest.getString("defaultpage");

                    Settings.Save();
                    output.writeBytes(construct_http_header_type(200, 0, 0));
                    break;
            }

        } catch (JSONException ex) {
            //java.util.logging.Logger.getLogger(Http_Handler.class.getName()).log(Level.SEVERE, null, ex);
            constructErrorPage(500);
        }
        output.close();

        if (oldWebport != Settings.webPort) {
            this.listener.createNewWebServer();
        }
        if (oldControlport != Settings.controlPort) {
            this.listener.createNewControlServer();
        }
    }

    public void getMethod(String request) {
        //tmp2 contains "GET /index.html HTTP/1.0 ......."
        //Parse the tmp
        log(request);
        int start = 0;
        int end = 0;
        for (int a = 0; a < request.length(); a++) {
            if (request.charAt(a) == ' ' && start != 0) {
                end = a;
                break;
            }
            if (request.charAt(a) == ' ' && start == 0) {
                start = a;
            }
        }
        path = request.substring(start + 2, end);
        if (path.equals("")) {
            if (server.getPort() == Settings.controlPort) {
                path = Settings.defaultPages[1];
            } else {
                path = Settings.defaultPages[0];
            }
        }
        if (path.equals("control.html")) {
            User u = DatabaseConnector.GetUser(getCookieUsername);
            if (u == null || u.getLogged() == 0) {
                try {
                    constructErrorPage(401);
                    return;
                } catch (IOException ex) {
                    java.util.logging.Logger.getLogger(Http_Handler.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            else{
                DatabaseConnector.LogUser(getCookieUsername, 0);
            }
        }
        String filepath = new File(path).getAbsolutePath();
        log("Client requested:" + filepath + "\n");

        FileInputStream requestedfile = null;

        try {
            //try to open the file
            requestedfile = new FileInputStream(path);
        } catch (Exception e) {
            try {
                //if you could not open the file send a 404
                constructErrorPage(404);
                return;
            } catch (Exception e2) {
                log("error on 404: " + e.getMessage());
            }
        }

        try {
            int type_is = 0;
            //find out what the filename ends with, so you can construct the right content type
            if (path.endsWith(".html")) {
                type_is = 1;
            } else if (path.endsWith(".jpg") || path.endsWith(".jpeg")) {
                type_is = 2;
            } else if (path.endsWith(".zip")) {
                type_is = 3;
            } else if (path.endsWith(".gif")) {
                type_is = 4;
            } else if (path.endsWith(".png")) {
                type_is = 5;
            } else if (path.endsWith(".js")) {
                type_is = 6;
            } else if (path.endsWith(".php")) {
                type_is = 7;
            }

            //header 200, ok!
            //Content-type
            byte[] fileByte = Files.readAllBytes(Paths.get(filepath));
            output.writeBytes(construct_http_header_type(200, type_is, fileByte.length));

            output.write(fileByte, 0, fileByte.length);
            output.flush();

            output.close();
            requestedfile.close();
        } catch (Exception e) {
            log(e.getMessage());
        }
    }

    //makes the HTTP header for the response
    private String construct_http_header_type(int return_code, int file_type, int content_length) throws IOException {
        String s = "HTTP/1.1 ";

        switch (return_code) {
            case 200:
                s = s + "200 OK";
                break;
            case 400:
                s = s + "400 Bad Request";
                break;
            case 403:
                s = s + "403 Forbidden";
                break;
            case 404:
                s = s + "404 Not Found";
                break;
            case 500:
                s = s + "500 Internal Server Error";
                break;
            case 501:
                s = s + "501 Not Implemented";
                break;
        }

        s = s + "\r\n"; //other header fields,
        s = s + "Connection: keep-alive\r\n"; //we can't handle persistent connections

        //Construct the right Content-Type for the header.
        log("Content-Type: " + file_type + "\n");
        switch (file_type) {
            case 0:
                s = s + "Content-Type: text/html";
                break;
            case 1:
                s = s + "Content-Type: text/html";
                break;
            case 2:
                s = s + "Content-Type: image/jpg";
                break;
            case 3:
                s = s + "Content-Type: application/x-zip-compressed";
            case 4:
                s = s + "Content-Type: image/gif";
                break;
            case 5:
                s = s + "Content-Type: image/png";
                break;
            case 6:
                s = s + "Content-Type: application/javascript";
                break;
            case 7:
                s = s + "Content-Type: text/html";
                break;
            default:
                s = s + "Content-Type: text/html";
                break;
        }
        s += "\r\n";

        s += "Content-Length: " + content_length + "\r\n";
        if(setCookie != null && !setCookie.isEmpty()){
            s+= setCookie;
        }
        else
        {
            setCookie = "";
        }
        s += "\r\n";

        return s;
    }

//  //makes the HTTP body for the response
//  private String construct_http_body(String request, String filepath) throws FileNotFoundException, IOException {
//    String s = "";
//    FileReader fr = new FileReader(filepath);
//    BufferedReader br = new BufferedReader(fr);
//    StringBuilder content = new StringBuilder(1024);
//    
//    while((s = br.readLine())!= null)
//    {
//        content.append(s);
//    }
//    
//    return content.toString();
//  }
    private void constructErrorPage(int errorcode) throws IOException {

        log(String.format("Http_header: %d\n", errorcode));
        String filepath = String.format("%s\\errorpages\\%d.html", Settings.webRoot, errorcode);
        System.out.println(filepath);
        byte[] fileByte = Files.readAllBytes(Paths.get(filepath));
        output.writeBytes(construct_http_header_type(errorcode, 0, fileByte.length));
        output.write(fileByte, 0, fileByte.length);
        output.flush();
        output.close();

    }
}
